package controller

import (
	"github.com/ethereum/go-ethereum/common"
	"github.com/gin-gonic/gin"
	"math/big"
	"net/http"
	"shendaNFT/pkg/model"
	"shendaNFT/pkg/web/util"
)

func (c *Controller) DeployBatch(ctx *gin.Context) {
	var params model.DeployBatchParam
	if err := ctx.ShouldBindJSON(&params); err != nil {
		ctx.JSON(http.StatusBadRequest, util.ErrorResponse(err.Error()))
		return
	}
	c.logger.Sugar().Debugw("deployParam", "param", params)
	data, err := c.client.DeployBatch(params)
	if err != nil {
		ctx.JSON(http.StatusOK, util.ErrorResponse(err.Error()))
		return
	}
	c.logger.Sugar().Debugw("deploy", "resp", data)
	ctx.JSON(http.StatusOK, util.SuccessResponse(data))
}

// Deploy 合约部署
func (c *Controller) Deploy(ctx *gin.Context) {
	var params model.DeployParam
	if err := ctx.ShouldBindJSON(&params); err != nil {
		ctx.JSON(http.StatusBadRequest, util.ErrorResponse(err.Error()))
		return
	}
	c.logger.Sugar().Debugw("deploy param", "param", params)
	data, err := c.client.Deploy(params)
	if err != nil {
		c.logger.Sugar().Debugw("deploy error", "owner", params.Owner, "name", params.Name, "error", err)
		ctx.JSON(http.StatusOK, util.ErrorResponse(err.Error()))
		return
	}
	c.logger.Sugar().Debugw("deploy result", "owner", params.Owner, "name", params.Name, "resp", data)
	ctx.JSON(http.StatusOK, util.SuccessResponse(data))
}

// Mint 铸造单个NFT
func (c *Controller) Mint(ctx *gin.Context) {
	var params model.MintParams
	if err := ctx.ShouldBindJSON(&params); err != nil {
		ctx.JSON(http.StatusBadRequest, util.ErrorResponse(err.Error()))
		return
	}
	c.logger.Sugar().Debugw("mint param", "param", params)
	items := make([]model.MintBatchParamItem, 1)
	items[0] = model.MintBatchParamItem{
		Owner:    params.Owner,
		TokenURI: params.TokenURI,
	}
	result, err := c.client.MintBatch(model.MintBatchParam{Contract: params.Contract, Items: items})
	if err != nil {
		ctx.JSON(http.StatusOK, util.ErrorResponse(err.Error()))
		return
	}
	c.logger.Sugar().Debugw("mint result", "resp", result)
	ctx.JSON(http.StatusOK, util.SuccessResponse(result[0]))
}

// MintBatch 批量铸造
func (c *Controller) MintBatch(ctx *gin.Context) {
	var params model.MintBatchParam
	if err := ctx.ShouldBindJSON(&params); err != nil {
		ctx.JSON(http.StatusBadRequest, util.ErrorResponse(err.Error()))
		return
	}
	c.logger.Sugar().Debugw("mintParam", "param", params)
	results, err := c.client.MintBatch(params)
	if err != nil {
		ctx.JSON(http.StatusOK, util.ErrorResponse(err.Error()))
		return
	}
	c.logger.Sugar().Debugw("mint", "resp", results)
	ctx.JSON(http.StatusOK, util.SuccessResponse(results))
}

// TransferFrom 所有权转移
func (c *Controller) TransferFrom(ctx *gin.Context) {
	var params model.TransferFromParams
	if err := ctx.ShouldBindJSON(&params); err != nil {
		ctx.JSON(http.StatusBadRequest, util.ErrorResponse(err.Error()))
		return
	}
	c.logger.Sugar().Debugw("transfer param", "param", params)
	contract := common.HexToAddress(params.Contract)
	from := common.HexToAddress(params.From)
	to := common.HexToAddress(params.To)
	tokenID := new(big.Int)
	tokenID.SetUint64(params.TokenID)
	transaction, err := c.client.TransferFrom(contract, from, to, tokenID)
	if err != nil {
		c.logger.Sugar().Debugw("transfer error", "error", err.Error(), "contract", params.Contract, "tokenID", params.TokenID)
		ctx.JSON(http.StatusOK, util.ErrorResponse(err.Error()))
		return
	}
	c.logger.Sugar().Debugw("transfer resp", "resp", transaction, "contract", params.Contract, "tokenID", params.TokenID)
	ctx.JSON(http.StatusOK, util.SuccessResponse(model.TransferResult{Transaction: *transaction}))
}

// TransferFromBatch 所有权转移
func (c *Controller) TransferFromBatch(ctx *gin.Context) {
	var params model.TransferFromBatchParams
	if err := ctx.ShouldBindJSON(&params); err != nil {
		ctx.JSON(http.StatusBadRequest, util.ErrorResponse(err.Error()))
		return
	}
	c.logger.Sugar().Debugw("transferBatch params", "param", params)

	transaction, errs := c.client.TransferFromBatch(params.Items)
	c.logger.Sugar().Debugw("transferBatch  resp", "resp", transaction)
	ctx.JSON(http.StatusOK, util.SuccessResponse(model.TransferBatchResult{Transactions: transaction, Errors: errs}))
}

// Burn 销毁NFT
func (c *Controller) Burn(ctx *gin.Context) {
	var params model.BurnParams
	if err := ctx.ShouldBindJSON(&params); err != nil {
		ctx.JSON(http.StatusBadRequest, util.ErrorResponse(err.Error()))
		return
	}
	c.logger.Sugar().Debugw("burn param", "param", params)
	contract := common.HexToAddress(params.Contract)
	tokenID := new(big.Int)
	tokenID.SetUint64(params.TokenID)
	transaction, err := c.client.Burn(contract, tokenID)
	if err != nil {
		ctx.JSON(http.StatusOK, util.ErrorResponse(err.Error()))
		c.logger.Sugar().Debugw("burn error", "error", err.Error())
		return
	}
	c.logger.Sugar().Debugw("burn resp", "resp", transaction)
	ctx.JSON(http.StatusOK, util.SuccessResponse(model.TransferResult{Transaction: *transaction}))
}

// OwnerOf NFT拥有者查询
func (c *Controller) OwnerOf(ctx *gin.Context) {
	var params model.OwnerOfParam
	if err := ctx.ShouldBindQuery(&params); err != nil {
		ctx.JSON(http.StatusBadRequest, util.ErrorResponse(err.Error()))
		return
	}
	contractAddress := common.HexToAddress(params.Address)
	tokenID := new(big.Int)
	tokenID.SetString(params.TokenID, 10)

	ownerAddress, err := c.client.OwnerOf(contractAddress, tokenID)
	if err != nil {
		ctx.JSON(http.StatusOK, util.ErrorResponse(err.Error()))
		return
	}
	ctx.JSON(http.StatusOK, util.SuccessResponse(ownerAddress.String()))
}

// TotalSupply 获取合约中NFT总数
func (c *Controller) TotalSupply(ctx *gin.Context) {
	address := ctx.Query("address")
	if len([]byte(address)) == 0 {
		ctx.JSON(http.StatusBadRequest, util.ErrorResponse("address is null"))
		return
	}
	total, err := c.client.TotalSupply(common.HexToAddress(address))
	if err != nil {
		ctx.JSON(http.StatusOK, util.ErrorResponse(err.Error()))
		return
	}
	ctx.JSON(http.StatusOK, util.SuccessResponse(total.Uint64()))
}
